/*
 * RWLock.cpp
 *
 *  Created on: Mar 23, 2012
 *      Author: s147614
 */

#include "RWLock.h"

RWLock::RWLock(int keuze, const char* type) :
	Monitor("RWLock", 2) {
	assert(keuze == 1 || keuze == 2 || keuze == 3);
	this->keuze = keuze;
	setName(type);
}

void	RWLock::dumpState( const char *mesg )
{
	//Thread *tp = Thread::currentThread();
	//cout << (*tp) << " "<<mesg<< " w="<<writers << " ww=" << wWriters << " r="<<readers<<" wr="<<wReaders<< endl;
}

void RWLock::rdlock() {

	ENTER();
	dumpState("rdlock begin");
	if (writers > 0) { // schrijver bezig
		++wReaders; // wachtende lezers
		WAIT(READER);
		--wReaders;
	}
	readers++; // active lezers
	dumpState("rdlock reading");
	LEAVE();

}

void RWLock::wrlock() {
	ENTER();
	dumpState("wrlock begin");
	if ( (writers > 0) // schrijver bezig
			|| (readers > 0) ) { // lezers bezig
		++wWriters;
		dumpState("wrlock wait");
		WAIT(WRITER);
		dumpState("wrlock goon");
		--wWriters;
	}
	assert(writers==0); // sanity-check
	writers++;
	dumpState("wrlock writing");
	assert(writers==1); // sanity-check
	LEAVE();

}

void RWLock::unlock() {
	ENTER();
	dumpState("unlock begin");
	if (readers > 0) { // ik ben een lezer
		--readers;
		if (readers == 0) // ik was de laatste
			kiesOpvolgers(); // wek de opvolger(s)
	} else {
		assert(writers==1); // sanity-check
		--writers;
		assert(writers==0); // sanity-check
		kiesOpvolgers();
	}
	dumpState("unlock done");
	LEAVE();
}

void RWLock::kiesOpvolgers() {
	switch (keuze) {
	case 1:
		keuze1();
		break;
	case 2:
		keuze2();
		break;
	case 3:
		keuze3();
		break;
	}
}

void RWLock::keuze1() {
	// Lezers gaan voor schrijvers
	if (wReaders > 0) {
		NOTIFYALL(READER);
	} else if (wWriters > 0) {
		NOTIFY(WRITER);
	}
}

void RWLock::keuze2() {
	// wachtende schrijvers gaan voor lezers
	if (wWriters > 0) {
		NOTIFY(WRITER);
	} else if (wReaders > 0) {
		NOTIFYALL(READER);
	}
}

void RWLock::keuze3() {
	if (wWriters == 1) { // maar 1 wachtende schrijver
		NOTIFY(WRITER);
	} else if (wReaders > 0) { // dan alle lezers
		NOTIFYALL(READER);
	} else {
		NOTIFY(WRITER); // de resterende schrijvers
	}
}

